package org.ruoyi.common.dhuman.rpc;

import java.io.File;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FFMpegDigitalHumanFusionProcessor {
    private String currentDir;
    private String timestamp;
    
    public FFMpegDigitalHumanFusionProcessor() {
        this.currentDir = Paths.get("").toAbsolutePath().toString();
        this.timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
    }
    
    private java.util.Map<String, String> getFilePaths() {
        java.util.Map<String, String> paths = new java.util.HashMap<>();
        paths.put("bg", Paths.get(currentDir, "bg.png").toString());
        paths.put("result_video", Paths.get(currentDir, "result.mp4").toString());
        paths.put("output", Paths.get(currentDir, "digital_human_presentation_" + timestamp + ".mp4").toString());
        return paths;
    }
    
    /**
     * 检查FFmpeg是否可用
     */
    private boolean isFFmpegAvailable() {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder("ffmpeg", "-version");
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取视频尺寸信息
     */
    private VideoInfo getVideoInfo(String videoPath) throws IOException, InterruptedException {
        List<String> command = new ArrayList<>();
        command.add("ffprobe");
        command.add("-v");
        command.add("error");
        command.add("-select_streams");
        command.add("v:0");
        command.add("-show_entries");
        command.add("stream=width,height");
        command.add("-of");
        command.add("csv=p=0");
        command.add(videoPath);
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = processBuilder.start();
        
        StringBuilder output = new StringBuilder();
        java.util.Scanner scanner = new java.util.Scanner(process.getInputStream());
        while (scanner.hasNextLine()) {
            output.append(scanner.nextLine());
        }
        scanner.close();
        
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IOException("无法获取视频信息");
        }
        
        String[] dimensions = output.toString().trim().split(",");
        if (dimensions.length >= 2) {
            return new VideoInfo(Integer.parseInt(dimensions[0]), Integer.parseInt(dimensions[1]));
        }
        
        throw new IOException("无法解析视频尺寸信息");
    }
    
    /**
     * 获取背景图片尺寸信息
     */
    private VideoInfo getbgInfo(String bgPath) throws IOException, InterruptedException {
        List<String> command = new ArrayList<>();
        command.add("ffprobe");
        command.add("-v");
        command.add("error");
        command.add("-select_streams");
        command.add("v:0");
        command.add("-show_entries");
        command.add("stream=width,height");
        command.add("-of");
        command.add("csv=p=0");
        command.add(bgPath);
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = processBuilder.start();
        
        StringBuilder output = new StringBuilder();
        java.util.Scanner scanner = new java.util.Scanner(process.getInputStream());
        while (scanner.hasNextLine()) {
            output.append(scanner.nextLine());
        }
        scanner.close();
        
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IOException("无法获取背景图片信息");
        }
        
        String[] dimensions = output.toString().trim().split(",");
        if (dimensions.length >= 2) {
            return new VideoInfo(Integer.parseInt(dimensions[0]), Integer.parseInt(dimensions[1]));
        }
        
        throw new IOException("无法解析背景图片尺寸信息");
    }
    
    /**
     * 执行FFmpeg命令进行视频融合
     */
    private void executeFFmpegCommand(List<String> command) throws IOException, InterruptedException {
        System.out.println("执行FFmpeg命令: " + String.join(" ", command));
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.inheritIO(); // 继承父进程的IO，显示FFmpeg的输出
        
        Process process = processBuilder.start();
        int exitCode = process.waitFor();
        
        if (exitCode != 0) {
            throw new IOException("FFmpeg命令执行失败，退出码: " + exitCode);
        }
    }
    
    /**
     * 处理绿幕数字人PPT融合任务
     */
    public void processGreenScreenDigitalHumanFusion() {
        System.out.println("开始处理绿幕数字人PPT融合任务...");
        
        if (!isFFmpegAvailable()) {
            System.err.println("错误: FFmpeg不可用，请确保已安装并添加到系统PATH中");
            return;
        }
        
        java.util.Map<String, String> paths = getFilePaths();
        
        // 检查输入文件是否存在
        if (!new File(paths.get("bg")).exists()) {
            System.err.println("错误: 背景图片不存在 - " + paths.get("bg"));
            return;
        }
        
        if (!new File(paths.get("result_video")).exists()) {
            System.err.println("错误: 数字人视频不存在 - " + paths.get("result_video"));
            return;
        }
        
        try {
            // 获取视频和背景图片信息
            VideoInfo videoInfo = getVideoInfo(paths.get("result_video"));
            VideoInfo bgInfo = getbgInfo(paths.get("bg"));
            
            System.out.println("数字人视频参数: 分辨率=" + videoInfo.width + "x" + videoInfo.height);
            System.out.println("背景图片参数: 分辨率=" + bgInfo.width + "x" + bgInfo.height);

			// 修改数字人参数计算部分
			// 计算数字人参数
			int digitalHumanWidth =  400;
			// 保持数字人宽高比，基于原始视频比例
			int digitalHumanHeight = (int) (((double) videoInfo.height / videoInfo.width) * digitalHumanWidth);
			int posX = bgInfo.width - digitalHumanWidth;
			int posY = bgInfo.height - digitalHumanHeight;

            System.out.println("数字人大小: " + digitalHumanWidth + "x" + digitalHumanHeight);
            System.out.println("数字人位置: (" + posX + ", " + posY + ")");
            
            // 构建FFmpeg命令
            List<String> command = new ArrayList<>();
            command.add("ffmpeg");
            command.add("-i");
			// 背景图片
            command.add(paths.get("bg"));
            command.add("-i");
			// 数字人视频
            command.add(paths.get("result_video"));
            
            // 设置背景图片循环
            command.add("-loop");
            command.add("1");

			// 修改滤镜_complex参数部分
			StringBuilder filterComplex = new StringBuilder();
			// 背景图片缩放到合适尺寸
			filterComplex.append("[0:v]scale=").append(bgInfo.width).append(":").append(bgInfo.height).append("[bg];");
			// 数字人视频先缩放再去除绿色背景
			filterComplex.append("[1:v]scale=").append(digitalHumanWidth).append(":").append(digitalHumanHeight).append(",chromakey=0x00b121:0.1:0.1[scaled_dh];");
			// 将处理后的数字人叠加到背景上
			filterComplex.append("[bg][scaled_dh]overlay=").append(posX).append(":").append(posY);
            
            command.add("-filter_complex");
            command.add(filterComplex.toString());
            
            // 设置输出参数
            command.add("-c:a");
			// 复制音频轨道
            command.add("copy");
			// 覆盖输出文件
            command.add("-y");
            command.add(paths.get("output"));
            
            // 执行FFmpeg命令
            executeFFmpegCommand(command);
            
            System.out.println("绿幕数字人PPT融合任务完成！输出文件: " + paths.get("output"));
            
            // 验证输出文件
            File outputFile = new File(paths.get("output"));
            if (outputFile.exists()) {
                double fileSize = outputFile.length() / (1024.0 * 1024.0);
                System.out.printf("输出文件大小: %.2f MB%n", fileSize);
            } else {
                System.err.println("警告: 输出文件可能未成功创建");
            }
            
        } catch (Exception e) {
            System.err.println("处理过程中发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        FFMpegDigitalHumanFusionProcessor processor = new FFMpegDigitalHumanFusionProcessor();
        processor.processGreenScreenDigitalHumanFusion();
    }
    
    // 视频信息内部类
    private static class VideoInfo {
        int width, height;
        
        public VideoInfo(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }
}
